package com.koushikdutta.async;

import com.koushikdutta.async.callback.CompletedCallback;
import com.koushikdutta.async.callback.DataCallback;
import com.koushikdutta.async.callback.WritableCallback;
import com.koushikdutta.async.wrapper.AsyncSocketWrapper;
import java.nio.ByteBuffer;

public class Util {
    static final /* synthetic */ boolean $assertionsDisabled = (!Util.class.desiredAssertionStatus());

    public static void emitAllData(DataEmitter emitter, ByteBufferList list) {
        DataCallback handler = null;
        while (!emitter.isPaused()) {
            handler = emitter.getDataCallback();
            if (handler == null) {
                break;
            }
            int remaining = list.remaining();
            if (remaining <= 0) {
                break;
            }
            handler.onDataAvailable(emitter, list);
            if (remaining == list.remaining() && handler == emitter.getDataCallback() && !emitter.isPaused()) {
                System.out.println("handler: " + handler);
                if ($assertionsDisabled) {
                    throw new RuntimeException("mDataHandler failed to consume data, yet remains the mDataHandler.");
                }
                throw new AssertionError();
            }
        }
        if (list.remaining() != 0 && !emitter.isPaused()) {
            System.out.println("handler: " + handler);
            System.out.println("emitter: " + emitter);
            if ($assertionsDisabled) {
                throw new RuntimeException("Not all data was consumed by Util.emitAllData");
            }
            throw new AssertionError();
        }
    }

    public static void pump(final DataEmitter emitter, final DataSink sink, final CompletedCallback callback) {
        final DataCallback dataCallback = new DataCallback() {
            public void onDataAvailable(DataEmitter emitter, ByteBufferList bb) {
                sink.write(bb);
                if (bb.remaining() > 0) {
                    emitter.pause();
                }
            }
        };
        emitter.setDataCallback(dataCallback);
        sink.setWriteableCallback(new WritableCallback() {
            public void onWriteable() {
                dataCallback.onDataAvailable(emitter, new ByteBufferList());
                emitter.resume();
            }
        });
        CompletedCallback wrapper = new CompletedCallback() {
            boolean reported;

            public void onCompleted(Exception ex) {
                if (!this.reported) {
                    emitter.setEndCallback(null);
                    sink.setClosedCallback(null);
                    sink.setWriteableCallback(null);
                    this.reported = true;
                    callback.onCompleted(ex);
                }
            }
        };
        emitter.setEndCallback(wrapper);
        sink.setClosedCallback(wrapper);
    }

    public static void writeAll(final DataSink sink, final ByteBufferList bb, final CompletedCallback callback) {
        WritableCallback wc = new WritableCallback() {
            public void onWriteable() {
                sink.write(bb);
                if (bb.remaining() == 0 && callback != null) {
                    sink.setWriteableCallback(null);
                    callback.onCompleted(null);
                }
            }
        };
        sink.setWriteableCallback(wc);
        wc.onWriteable();
    }

    public static void writeAll(DataSink sink, byte[] bytes, CompletedCallback callback) {
        ByteBuffer bb = ByteBufferList.obtain(bytes.length);
        bb.put(bytes);
        bb.flip();
        ByteBufferList bbl = new ByteBufferList();
        bbl.add(bb);
        writeAll(sink, bbl, callback);
    }

    public static <T extends AsyncSocket> T getWrappedSocket(AsyncSocket socket, Class<T> wrappedClass) {
        if (wrappedClass.isInstance(socket)) {
            return socket;
        }
        while (socket instanceof AsyncSocketWrapper) {
            socket = ((AsyncSocketWrapper) socket).getSocket();
            if (wrappedClass.isInstance(socket)) {
                return socket;
            }
        }
        return null;
    }
}
